﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace XMouse360
{
	public class GamePadEventGenerator
	{

		private GamePadState controller;
		private GamePadState oldController;
		private PlayerIndex gamePadIndex;
		private Tuple<float, float> vibration;
		private bool stopFlag = false;


		//public static TesterForm testform = new TesterForm();

		private int refreshPeriod;

		public delegate void ControllerInputEventHandler(object sender, ControllerInputEventArgs e);


		public GamePadEventGenerator()
		{
			controller = new GamePadState();
			oldController = new GamePadState();
			GamePadIndex = 1;
			Vibration = new Tuple<float, float>(0f, 0f);
			stopFlag = false;
			RefreshPeriod = 10;
		}


		public GamePadEventGenerator(int GamePadIndex, int RefreshPeriod)
		{
			controller = new GamePadState();
			oldController = new GamePadState();
			this.GamePadIndex = GamePadIndex;
			Vibration = new Tuple<float, float>(0f, 0f);
			stopFlag = false;
			this.RefreshPeriod = RefreshPeriod;
		}


		public int GamePadIndex
		{
			get
			{
				switch (gamePadIndex)
				{
					case PlayerIndex.One: return 1;
					case PlayerIndex.Two: return 2;
					case PlayerIndex.Three: return 3;
					case PlayerIndex.Four: return 4;
					default: return 0;
				}
			}
			set
			{
				switch (value)
				{
					case 1: gamePadIndex = PlayerIndex.One; break;
					case 2: gamePadIndex = PlayerIndex.Two; break;
					case 3: gamePadIndex = PlayerIndex.Three; break;
					case 4: gamePadIndex = PlayerIndex.Four; break;
					default: throw new ArgumentOutOfRangeException("GamePadIndex", value,
						"Acceptable values of the variable are 1 through 4 inclusive.");
				}
			}
		}


		public int RefreshPeriod
		{
			get
			{
				return refreshPeriod;
			}
			set
			{
				refreshPeriod = value;
			}
		}


		public Tuple<float, float> Vibration
		{
			get
			{
				return new Tuple<float, float>(vibration.Item1, vibration.Item2);
			}
			set
			{
				GamePad.SetVibration(gamePadIndex, value.Item1, value.Item2);
				vibration = new Tuple<float, float>(value.Item1, value.Item2);
			}
		}


		public bool IsControllerConnected(PlayerIndex index)
		{
			return GamePad.GetState(index).IsConnected;
			
		}

		#region Public Events
		public event ControllerInputEventHandler AButtonPressed;
		public event ControllerInputEventHandler AButtonReleased;
		public event ControllerInputEventHandler BButtonPressed;
		public event ControllerInputEventHandler BButtonReleased;
		public event ControllerInputEventHandler XButtonPressed;
		public event ControllerInputEventHandler XButtonReleased;
		public event ControllerInputEventHandler YButtonPressed;
		public event ControllerInputEventHandler YButtonReleased;
		public event ControllerInputEventHandler BackButtonPressed;
		public event ControllerInputEventHandler BackButtonReleased;
		public event ControllerInputEventHandler StartButtonPressed;
		public event ControllerInputEventHandler StartButtonReleased;
		public event ControllerInputEventHandler LeftShoulderPressed;
		public event ControllerInputEventHandler LeftShoulderReleased;
		public event ControllerInputEventHandler RightShoulderPressed;
		public event ControllerInputEventHandler RightShoulderReleased;
		public event ControllerInputEventHandler DPadUpPressed;
		public event ControllerInputEventHandler DPadUpReleased;
		public event ControllerInputEventHandler DPadDownPressed;
		public event ControllerInputEventHandler DPadDownReleased;
		public event ControllerInputEventHandler DPadLeftPressed;
		public event ControllerInputEventHandler DPadLeftReleased;
		public event ControllerInputEventHandler DPadRightPressed;
		public event ControllerInputEventHandler DPadRightReleased;
		public event ControllerInputEventHandler LeftStickPressed;
		public event ControllerInputEventHandler LeftStickReleased;
		public event ControllerInputEventHandler RightStickPressed;
		public event ControllerInputEventHandler RightStickReleased;
		public event ControllerInputEventHandler LeftTriggerPulled;
		public event ControllerInputEventHandler RightTriggerPulled;
		public event ControllerInputEventHandler LeftStickDisplaced;
		public event ControllerInputEventHandler RightStickDisplaced;
		public event ControllerInputEventHandler Connected;
		public event ControllerInputEventHandler Disconnected;
		#endregion


		public void Run()
		{
			stopFlag = false;
			new System.Threading.Thread(eventGeneratorLoop).Start();

		}


		public void Stop()
		{
			stopFlag = true;
		}


		private void eventGeneratorLoop()
		{
			while (!stopFlag)
			{
				controller = GamePad.GetState(gamePadIndex, GamePadDeadZone.Circular);

				if (controller.IsConnected != oldController.IsConnected)
				{
					if (controller.IsConnected == true)
					{
						Connected.Invoke(controller, new ControllerInputEventArgs(true, "IsConnected"));
						
					}
					else
					{
						Disconnected.Invoke(controller, new ControllerInputEventArgs(false, "IsConnected"));
						
						System.Threading.Thread.Sleep(100);
						continue;
					}
				}


				//---------BOOLEANS---------//
				if (!controller.Buttons.A.Equals(oldController.Buttons.A))
				{
					if (controller.Buttons.A == ButtonState.Pressed)
					{
						AButtonPressed.Invoke(controller, new ControllerInputEventArgs(true, "A"));
						
					}
					else
					{
						AButtonReleased.Invoke(controller, new ControllerInputEventArgs(false, "A"));
						
					}
				}
				if (!controller.Buttons.B.Equals(oldController.Buttons.B))
				{
					if (controller.Buttons.B == ButtonState.Pressed)
					{
						BButtonPressed.Invoke(controller, new ControllerInputEventArgs(true, "B"));
						
					}
					else
					{
						BButtonReleased.Invoke(controller, new ControllerInputEventArgs(false, "B"));
						
					}
				}
				if (!controller.Buttons.X.Equals(oldController.Buttons.X))
				{
					if (controller.Buttons.X == ButtonState.Pressed)
					{
						XButtonPressed.Invoke(controller, new ControllerInputEventArgs(true, "X"));
						
					}
					else
					{
						XButtonReleased.Invoke(controller, new ControllerInputEventArgs(false, "X"));
						
					}
				}
				if (!controller.Buttons.Y.Equals(oldController.Buttons.Y))
				{
					if (controller.Buttons.Y == ButtonState.Pressed)
					{
						YButtonPressed.Invoke(controller, new ControllerInputEventArgs(true, "Y"));
						
					}
					else
					{
						YButtonReleased.Invoke(controller, new ControllerInputEventArgs(false, "Y"));
						
					}
				}
				if (!controller.Buttons.Back.Equals(oldController.Buttons.Back))
				{
					if (controller.Buttons.Back == ButtonState.Pressed)
					{
						BackButtonPressed.Invoke(controller, new ControllerInputEventArgs(true, "Back"));
						
					}
					else
					{
						BackButtonReleased.Invoke(controller, new ControllerInputEventArgs(false, "Back"));
						
					}
				}
				if (!controller.Buttons.Start.Equals(oldController.Buttons.Start))
				{
					if (controller.Buttons.Start == ButtonState.Pressed)
					{
						StartButtonPressed.Invoke(controller, new ControllerInputEventArgs(true, "Start"));
						
					}
					else
					{
						StartButtonReleased.Invoke(controller, new ControllerInputEventArgs(false, "Start"));
						
					}
				}
				if (!controller.Buttons.LeftShoulder.Equals(oldController.Buttons.LeftShoulder))
				{
					if (controller.Buttons.LeftShoulder == ButtonState.Pressed)
					{
						LeftShoulderPressed.Invoke(controller, new ControllerInputEventArgs(true, "LeftShoulder"));
						
					}
					else
					{
						LeftShoulderReleased.Invoke(controller, new ControllerInputEventArgs(false, "LeftShoulder"));
						
					}
				}
				if (!controller.Buttons.RightShoulder.Equals(oldController.Buttons.RightShoulder))
				{
					if (controller.Buttons.RightShoulder == ButtonState.Pressed)
					{
						RightShoulderPressed.Invoke(controller, new ControllerInputEventArgs(true, "RightShoulder"));
						
					}
					else
					{
						RightShoulderReleased.Invoke(controller, new ControllerInputEventArgs(false, "RightShoulder"));
						
					}
				}
				if (!controller.DPad.Up.Equals(oldController.DPad.Up))
				{
					if (controller.DPad.Up == ButtonState.Pressed)
					{
						DPadUpPressed.Invoke(controller, new ControllerInputEventArgs(true, "DPadUp"));
						
					}
					else
					{
						DPadUpReleased.Invoke(controller, new ControllerInputEventArgs(false, "DPadUp"));
						
					}
				}
				if (!controller.DPad.Down.Equals(oldController.DPad.Down))
				{
					if (controller.DPad.Down == ButtonState.Pressed)
					{
						DPadDownPressed.Invoke(controller, new ControllerInputEventArgs(true, "DPadDown"));
						
					}
					else
					{
						DPadDownReleased.Invoke(controller, new ControllerInputEventArgs(false, "DPadDown"));
						
					}
				}
				if (!controller.DPad.Left.Equals(oldController.DPad.Left))
				{
					if (controller.DPad.Left == ButtonState.Pressed)
					{
						DPadLeftPressed.Invoke(controller, new ControllerInputEventArgs(true, "DPadLeft"));
						
					}
					else
					{
						DPadLeftReleased.Invoke(controller, new ControllerInputEventArgs(false, "DPadLeft"));
						
					}
				}
				if (!controller.DPad.Right.Equals(oldController.DPad.Right))
				{
					if (controller.DPad.Right == ButtonState.Pressed)
					{
						DPadRightPressed.Invoke(controller, new ControllerInputEventArgs(true, "DPadRight"));
						
					}
					else
					{
						DPadRightReleased.Invoke(controller, new ControllerInputEventArgs(false, "DPadRight"));
						
					}
				}
				if (!controller.Buttons.LeftStick.Equals(oldController.Buttons.LeftStick))
				{
					if (controller.Buttons.LeftStick == ButtonState.Pressed)
					{
						LeftStickPressed.Invoke(controller, new ControllerInputEventArgs(true, "LeftStickButton"));
						
					}
					else
					{
						LeftStickReleased.Invoke(controller, new ControllerInputEventArgs(false, "LeftStickButton"));
						
					}
				}
				if (!controller.Buttons.RightStick.Equals(oldController.Buttons.RightStick))
				{
					if (controller.Buttons.RightStick == ButtonState.Pressed)
					{
						RightStickPressed.Invoke(controller, new ControllerInputEventArgs(true, "RightStickButton"));
						
					}
					else
					{
						RightStickReleased.Invoke(controller, new ControllerInputEventArgs(false, "RightStickButton"));
						
					}
				}

				//----------FLOATS----------//
				if (controller.Triggers.Left != 0 || controller.Triggers.Left != oldController.Triggers.Left)
				{
					LeftTriggerPulled.Invoke(controller, new ControllerInputEventArgs(controller.Triggers.Left,"LeftTrigger"));
					
				}
				if (controller.Triggers.Right != 0 || controller.Triggers.Right != oldController.Triggers.Right)
				{
					RightTriggerPulled.Invoke(controller, new ControllerInputEventArgs(controller.Triggers.Right,"RightTrigger"));
					
				}
				if (controller.ThumbSticks.Left.X != 0f || controller.ThumbSticks.Left.Y != 0f ||
					controller.ThumbSticks.Left.X != oldController.ThumbSticks.Left.X ||
					controller.ThumbSticks.Left.Y != oldController.ThumbSticks.Left.Y)
				{
					LeftStickDisplaced.Invoke(controller, new ControllerInputEventArgs(controller.ThumbSticks.Left.X, controller.ThumbSticks.Left.Y,"LeftStick"));
					
				}
				if (controller.ThumbSticks.Right.X != 0f || controller.ThumbSticks.Right.Y != 0f || 
					controller.ThumbSticks.Right.X != oldController.ThumbSticks.Right.X ||
					controller.ThumbSticks.Right.Y != oldController.ThumbSticks.Right.Y)
				{
					RightStickDisplaced.Invoke(controller, new ControllerInputEventArgs(controller.ThumbSticks.Right.X, controller.ThumbSticks.Right.Y,"RightStick"));
					
				}


				oldController = controller;
				//testform updates
				





				System.Threading.Thread.Sleep(RefreshPeriod);
			} // end while
		}

		/*private void UpdateTester()
		{
			testform.ClearItems();
			testform.AddItem("A: " + (controller.Buttons.A == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("B: " + (controller.Buttons.B == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("X: " + (controller.Buttons.X == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("Y: " + (controller.Buttons.Y == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("Back: " + (controller.Buttons.Back == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("Start: " + (controller.Buttons.Start == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("DPadUp: " + (controller.DPad.Up == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("DPadDown: " + (controller.DPad.Down == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("DPadLeft: " + (controller.DPad.Left == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("DPadRight: " + (controller.DPad.Right == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("LeftShoulder: " + (controller.Buttons.LeftShoulder == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("RightShoulder: " + (controller.Buttons.RightShoulder == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("LeftStick: " + (controller.Buttons.LeftStick == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("RightStick: " + (controller.Buttons.RightStick == ButtonState.Pressed ? "Pressed" : "Released"));
			testform.AddItem("LeftTrigger: " + controller.Triggers.Left);
			testform.AddItem("RightTrigger: " + controller.Triggers.Right);
			testform.AddItem(("LeftStickValue: " + controller.ThumbSticks.Left.X + ", " + controller.ThumbSticks.Left.Y));
			testform.AddItem(("RightStickValue: " + controller.ThumbSticks.Right.X + ", " + controller.ThumbSticks.Right.Y));
		}*/
	}

	public class ControllerInputEventArgs : EventArgs
	{
		public float XAxis { get; set; }
		public float YAxis { get; set; }
		public Boolean ButtonPressed { get; set; }
		public float TriggerAxis { get; set; }
		public ControllerInputType type { get; set; }
		public string Name { get; set; }

		public ControllerInputEventArgs(bool pressed, string Name)
		{
			type = ControllerInputType.ButtonPressed;
			ButtonPressed = pressed;
			this.Name = Name;
		}

		public ControllerInputEventArgs(float triggerValue, string Name)
		{
			type = ControllerInputType.TriggerPulled;
			TriggerAxis = triggerValue;
			this.Name = Name;
		}

		public ControllerInputEventArgs(float stickXAxis, float stickYAxis, string Name)
		{
			type = ControllerInputType.StickDisplaced;
			XAxis = stickXAxis;
			YAxis = stickYAxis;
			this.Name = Name;
		}
	}

	public enum ControllerInputType : byte
	{
		ButtonPressed,
		TriggerPulled,
		StickDisplaced
	}
}
